/*
 * @Author: 王汝鹏
 * @Date: 2021-01-05 10:40:37
 * @LastEditTime: 2021-01-07 14:03:44
 * @LastEditors: Please set LastEditors
 * @Description: 绘制直线/弧线程序
 * @FilePath: \mock_-device_-data\test3.js
 */




//  绘制一条直线
const draw_line = function(board, p1, p2) {
  //  如果是竖直的线,则无法生成关于xy的函数,直接使用坐标点值进行绘制即可
  if ((p2.x-p1.x) == 0) {
    let x   = p1.x;
    let min = Math.min(p1.y, p2.y);
    let max = Math.max(p1.y, p2.y);
    for (let y=min; y<=max; y++) {
      board[y][x] = '*';
    }
    return;
  }

  //  推导直线公式 ax + b = y;
  //  1a  + b = 1
  //  40a + b = 40
  //  a = (40-1) / (40-1) = 1
  //  b = 1 - (1*1) = 0
  //  f => 1*x + 0 = y
  let a = (p2.y-p1.y) / (p2.x-p1.x);
  let b = p1.y - (p1.x*a);

  //  通过宽高差值计算绘制方式,确保点的密集性(因为x+1对应的y如果变化很大会产生点之间很大的空隙)
  //  a的绝对值大于1,则以y为变化点找x对应点
  if (Math.abs(a) > 1) {
    let min = Math.min(p1.y, p2.y);
    let max = Math.max(p1.y, p2.y);
    
    for (let y=min; y<=max; y++) {
      //  f => ax+b=y;
      let x = Math.round((y-b)/a);
      board[y][x] = '*';
    }
  } else {
  //  a的绝对值小于1,则以x为变化点找y对应点
    let min = Math.min(p1.x, p2.x);
    let max = Math.max(p1.x, p2.x);
    
    for (let x=min; x<=max; x++) {
      //  f => ax+b=y;
      let y = Math.round(a*x+b);
      board[y][x] = '*';
    }
  }
}
//  绘制一条弧线
const draw_arc = function(board, p1, p2, p3) {
  //  ax² + bx + c = y
  //  假设 p1={1,1}, p2={2,2}, p3={3,4}
  //  a  + b  + c = 1
  //  4a + 2b + c = 2
  //  9a + 3b + c = 4
  //  p2 - p1 => 3a + b  = 1
  //  p3 - p1 => 8a + 2b = 3
  //  (p3-p1) - 2(p2-p1) => 2a = 1
  //  a = 1/2
  //  b = -(1/2)
  //  c = 1
  //  -----
  //  1/2 - (1/2) + 1 = 1
  //  4*(1/2) - 2*(1/2) + 1 = 2
  //  9*(1/2) - 3*(1/2) + 1 = 4
  //  假设 x=4, y = (1/2)*16 - (1/2)*4 + 1 = 7
  //  {4, 7}
  // 
  //  ----------
  //  假设 p1={0,1}, p2={1,2}, p3={2,4}
  //  c = 1
  //  a  + b  + 1 = 2  => 2a + 2b + 2 = 4
  //  4a + 2b + 1 = 4
  //  p3 - 2*p2 => 2a - 1 = 0
  //  a = 1/2
  //  b = 1/2
  //  c = 1
  //  -----
  //  0 + 0 + 1 = 1
  //  (1/2) + (1/2) + 1 = 2
  //  4*(1/2) + 2*(1/2) + 1 = 4
  //  假设 x=3, y = (1/2)*9 + (1/2)*3 + 1 = 7
  //  {3, 7}
  // 

  //  将弧线以p1点为基准点移动到x=0位置
  let offset = p1.x
  p1.x = 0;
  p2.x = p2.x - offset;
  p3.x = p3.x - offset;

  //  ax² + bx + c = y
  //  由 p1{0,y} 得 c=y
  //  (p3.x*p2) - (p2.x*p3)
  //  p2={1,2} => (p3.x*p2) => 2*(a+b+1)   = 2*2 => 2a+2b+2 = 4 => p3.x*p2.x*p2.x*a + p3.x*p2.x*b + p3.x*c = p3.x*p2.y
  //  p3={2,4} => (p2.x*p3) => 1*(4a+2b+1) = 1*4 => 4a+2b+1 = 4 => p2.x*p3.x*p3.x*a + p2.x*p3.x*b + p2.x*c = p2.x*p3.y
  //  (p3.x*p2) - (p2.x*p3) => -2a+1 = 0 => a = (1/2) => a = ((p3.x*p2.y-p2.x*p3.y) - (p3.x*c-p2.x*c)) / (p3.x*p2.x*p2.x-p2.x*p3.x*p3.x)
  let c = p1.y;
  let a = ((p3.x*p2.y-p2.x*p3.y)-(p3.x*c-p2.x*c)) / (p3.x*p2.x*p2.x-p2.x*p3.x*p3.x);
  let b = (p2.y - a*p2.x*p2.x - c) / p2.x;

  //  绘制p1~p2弧线
  let min = Math.min(p1.x, p2.x);
  let max = Math.max(p1.x, p2.x);
  for(let x=min; x<=max; x++) {
    let y = Math.round(a*x*x + b*x + c);
    board[y][x+offset] = '*';
  }
  //  绘制p2~p3弧线
  min = Math.min(p2.x, p3.x);
  max = Math.max(p2.x, p3.x);
  for(let x=min; x<=max; x++) {
    let y = Math.round(a*x*x + b*x + c);
    board[y][x+offset] = '*';
  }
}
//  打印图像
const print_graph = function(board, w, h) {
  for (let r=0; r<h; r++) {
    let line_data = "";
    for (let c=0; c<w; c++) {
      line_data += board[r][c];
    }
    console.log(line_data);
  }
}



const ROW_LENGTH = 20;
const COLUMN_LENGTH = 20;

//  画板初始化, 创建二维数组 width * height
let board = new Array(ROW_LENGTH);
for (let r=0; r<ROW_LENGTH; r++) {
  board[r] = new Array(COLUMN_LENGTH);
  board[r].fill(" ");
}
//****************************
//  绘制直线
// //  绘制一条直线
// let point_1 = { x:0,  y:0  };
// let point_2 = { x:19, y:10 };
// draw_line(board, point_1, point_2);
// //  绘制一条直线
// point_1 = { x:19, y:10  };
// point_2 = { x:1,  y:10 };
// draw_line(board, point_1, point_2);
// //  绘制一条直线
// point_1 = { x:1, y:10  };
// point_2 = { x:0, y:0 };
// draw_line(board, point_1, point_2);
// //  打印图像
// print_graph(board, ROW_LENGTH, COLUMN_LENGTH);

//****************************
//  绘制弧线
let point_1 = { x:1,  y:1 };
let point_2 = { x:19, y:1 };
let point_3 = { x:9,  y:10 };
draw_arc(board, point_1, point_2, point_3);
//  打印图像
print_graph(board, ROW_LENGTH, COLUMN_LENGTH);


